﻿/****************************************************************************
** \file ParamProcesser.cpp
** \company PONGBOT
**
** \author houhaotian
** \date 2020/08/26
**
** \brief 读取所有元对象的属性，按照<对象名/属性名,QVariant>的方式存到QSettings.
**        在设置objectname的时候自动读取内容，在属性变更时自动保存值。
**
** TODO:  目前为析构时保存属性值。变更为1min存一次。最好是或得通知实时存。
**
****************************************************************************/
#include "ParamProcesser.h"
#include <QCoreApplication>
#include <QSettings>
#include <QMetaObject>
#include <QMetaProperty>
#include <QTimer>
#include <QDebug>

ParamProcesser::ParamProcesser(QObject *parent /*= nullptr*/)
    : QObject(parent)
{
    m_settings = new QSettings(QCoreApplication::applicationDirPath() + "/parameters/params.ini", QSettings::IniFormat, this);
    m_settings->setIniCodec("UTF-8");
    connect(this, &ParamProcesser::objectNameChanged, this, &ParamProcesser::onObjectNameChanged);
    //m_timer = new QTimer(this);
    //m_timer->start(5 * 1000);//5s存一次
    //m_timer->callOnTimeout(this, &ParamProcesser::saveProperties);

    QMetaObject::invokeMethod(this, [this] {
        const QMetaObject *metaObject = this->metaObject();
        for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
            const char *propertyName = metaObject->property(i).name();
            ReceiverPrivate *receiver = new ReceiverPrivate(propertyName, this);
            connect(receiver, &ReceiverPrivate::propertyChanged, this, &ParamProcesser::saveProperty);
        }
		}, Qt::QueuedConnection);
	
}

ParamProcesser::~ParamProcesser()
{
    //m_timer->stop();
    saveProperties();
}

void ParamProcesser::onObjectNameChanged(const QString &objectName)
{
    const QMetaObject *metaObject = this->metaObject();
    for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
        auto property = metaObject->property(i);
        //枚举值在元对象系统中以int存储。但不能写入QVariant<QString>。
        if (property.isEnumType())
            property.write(this, m_settings->value(objectName + "/" + property.name()).toInt());

        else if (property.write(this, m_settings->value(objectName + "/" + property.name())) == false)
            qDebug() << "write property false";
    }
}

void ParamProcesser::saveProperties()
{
    const QMetaObject *metaObject = this->metaObject();
    for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
        auto property = metaObject->property(i);
        m_settings->setValue(objectName() + "/" + property.name(), property.read(this));
    }
}

void ParamProcesser::saveProperty(const char *property)
{
	QMetaProperty metaProperty = metaObject()->property(metaObject()->indexOfProperty(property));
	m_settings->setValue(objectName() + "/" + metaProperty.name(), metaProperty.read(this));

	qDebug() << "saveProperty:" << metaProperty.name() << metaProperty.read(this);
}

//返回所有属性名,格式为objectName/name
QStringList ParamProcesser::allPropertiesName()
{
    const QMetaObject *metaObject = this->metaObject();
    QStringList ret;
    for (int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i) {
        auto property = metaObject->property(i);
		ret.append(objectName() + "/" + property.name());
    }
    return ret;
}

ReceiverPrivate::ReceiverPrivate(const char *property, QObject *parent)
	: m_property(property)
	, QObject(parent)
{
	const QMetaObject *metaObj = parent->metaObject();
	QMetaProperty metaProperty = metaObj->property(metaObj->indexOfProperty(property));
    QMetaMethod sig = metaProperty.notifySignal();
    if (sig.isValid()) {
		QMetaMethod slot = this->metaObject()->method(this->metaObject()->indexOfSlot("onPropertyChanged()"));
		connect(parent, sig, this, slot);
    }
}
